package net.vsame.url2sql.web.bigpipe;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.vsame.url2sql.helper.FileUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class BigPipeHelper {
	
	static String contentPath = "";
	private static String JSBase = "";
	private static String CSSBase = "";
	private static String IMAGEBase = "";
	private static ConfigComm configComm = null;
	private static Set<BigpipeCode> smartCodes = new HashSet<BigpipeCode>();
	
	/**
	 * 处理 img标签, a标签 
	 * @param str
	 * @param basePath
	 * @return
	 */
	private static String hanldImgA(String str, String basePath){
		List<T> list = findScrit(str);
		//处理<a><img>
		StringBuffer sb = new StringBuffer();
		Pattern p = Pattern.compile("<img[\\s\\S]*?src[\\s]*?\\=[\\s]*?['\"](.*?)['|\"][\\s\\S]*?>|<a[\\s\\S]*?href[\\s]*?\\=[\\s]*?['\"](.*?)['|\"][\\s\\S]*?>");
		Matcher m = p.matcher(str);
		a : while(m.find()){
			int start = m.start();
			for(T t : list){
				if(start>t.min && start<t.max){
					continue a;
				}
			}
			String all = m.group();
	    	String tempUrl = m.group(1);
	    	String base = IMAGEBase;
	    	
	    	boolean isSelf = false;//是否为#号开始
	    	if(tempUrl==null){
	    		tempUrl = m.group(2);
	    		base = contentPath;
	    		if(tempUrl.startsWith("#")){
	    			isSelf = true;
	    		}
	    	}
	    	String t = all;
	    	if(!isSelf && !isAbsolute(tempUrl)){//不是以http:// ftp:// thunder:// gaollg:// ...
	    		t = all.replace(tempUrl, base + calcRelativePath(basePath, tempUrl));
	    	}
    		m.appendReplacement(sb, t.replace("$", "\\$"));
		}
		 m.appendTail(sb);
		return sb.toString();
	}
	
	/**
	 * 
	 * @param file
	 * @param basePath
	 * @param endBody 是否以&lt;/body&gt;结束
	 * @return
	 */
	public static String readHtml(File file, String basePath, boolean endBody) {
		String str = null;
		Pattern p = Pattern.compile("<script.*? src\\=('|\")(.*?)('|\")(.|\\s)*?>|<link.*? href\\=('|\")(.*?)('|\")(.|\\s)*?>|<script.*? include\\=('|\")(.*?)('|\")(.|\\s)*?>");
		if(endBody){
			str = FileUtils.readEndBody(file);
		}else{
			str = FileUtils.readAllText(file);
		}

	    Matcher m = p.matcher(str);
	    StringBuffer sb = new StringBuffer();
	    while(m.find()){
	    	String all = m.group();
	    	String tempUrl = m.group(2);
	    	if(tempUrl != null){//这是加载js
	    		String t = all;
	    		if(!isAbsolute(tempUrl)){//不是以http:// ftp:// thunder:// gaollg:// ...
		    		t = all.replace(tempUrl, JSBase + calcRelativePath(basePath, tempUrl));
		    	}
	    		m.appendReplacement(sb, t.replace("$", "\\$"));
	    		continue;
	    	}
	    	tempUrl = m.group(6);
	    	if(tempUrl != null){//这是加载css
	    		String t = all;
	    		if(!isAbsolute(tempUrl)){//不是以http:// ftp:// thunder:// gaollg:// ...
		    		t = all.replace(tempUrl, CSSBase + calcRelativePath(basePath, tempUrl));
		    	}
	    		m.appendReplacement(sb, t.replace("$", "\\$"));
	    		continue;
	    	}
	    	tempUrl = m.group(10);
	    	if(tempUrl != null){//这是包含js include
	    		File inculdeFile = null;
	    		if(tempUrl.startsWith("/")){//绝对路径...
	    			inculdeFile = new File(BigpipeHandler.realPath + tempUrl);
	    			if(inculdeFile.exists()){
	    				String t = readHtml(inculdeFile, getParentPath(tempUrl), false);
	    				m.appendReplacement(sb, t.replace("$", "\\$"));
	    			}else{
	    				throw new RuntimeException("The includePath \"" + tempUrl + "\" not exist.");
	    			}
	    		}else{
	    			inculdeFile = new File(file.getParent(), tempUrl);
	    			if(inculdeFile.exists()){
	    				String t = readHtml(inculdeFile, calcRelativePath(basePath, getParentPath(tempUrl)), false);
	    				m.appendReplacement(sb, t.replace("$", "\\$"));
	    			}else{
	    				throw new RuntimeException("The includePath \"" + tempUrl + "\" not exist.");
	    			}
	    		}
	    		continue;
	    	}
	    }
	    m.appendTail(sb);
	    return hanldImgA(sb.toString(), basePath);
	}
	
	private static String getParentPath(String url){
		int i = url.lastIndexOf("/");
		if(i==-1){
			return "";
		}
		return url.substring(0, i);
	}
	
	/**
	 * 寻找 &ltscript&gt &lt/script&gt 段
	 * @param str
	 * @return
	 */
	private static List<T> findScrit(String str){
		List<T> list = new ArrayList<T>();
		Pattern p = Pattern.compile("(<script[\\s\\S]*?<\\s*?/\\s*?script\\s*?>)");
		Matcher m = p.matcher(str);
		while(m.find()){
			T t = new T(m.start(), m.end());
			list.add(t);
		}
		return list;
	}
	
	private static class T {
		int min, max;

		public T(int min, int max) {
			this.min = min;
			this.max = max;
		}
	}
	/**
	 * 计算相对路径
	 * @param basePath
	 * @param relativePath
	 * @return
	 */
	private static String calcRelativePath(String basePath, String relativePath){
		String tempUrl = relativePath;
		String realDir = basePath;
		if(tempUrl.startsWith("./")){
			tempUrl = tempUrl.substring(2);
		}
		while (tempUrl.startsWith("../")) {
			int i = realDir.lastIndexOf("/");
			if(i!=-1){
				realDir = realDir.substring(0, i);
				tempUrl = tempUrl.substring(3);//删掉前面的../
			}else{
				return "/" + tempUrl;
			}
		}
		if(tempUrl==null || "".equals(tempUrl)){
			return realDir;
		}
		return realDir + "/" + tempUrl;
	}
	
	/**
	 * 判断是否为绝对路径
	 * <p>绝对路径分为两种</p>
	 * <p>1,以/开始.</br>2,以 "http://" "ftp://" 之类的协议开始</p>
	 * @param str
	 * @return
	 */
	private static boolean isAbsolute(String str){
		return str.matches("(^[a-zA-Z_]*?://.*)|(^/.*?)");
	}
	
	public static void setCommInfo(ConfigComm comm){
		BigPipeHelper.configComm = comm;
	}
	
	static String getCommScript(HttpServletRequest request, HttpServletResponse response){
		StringBuffer sb = new StringBuffer();
		sb.append("<script type=\"text/javascript\">\r\n");
		
		String contextPath = request.getContextPath();
		if(contextPath == null){
			contextPath = "";
		}
		sb.append("var CONFIG={}, smartCode={};\r\n");
		sb.append("var contextPath='" + contextPath + "';\r\n");
		sb.append("var cssPath='" + CSSBase + "';\r\n");
		sb.append("var jsPath='" + JSBase + "';\r\n");
		sb.append("var imagePath='" + IMAGEBase + "';\r\n");
		if(configComm != null){
			Map<String, Object> comm = new LinkedHashMap<String,Object>();
			configComm.configComm(comm, request, response);
			for(String key : comm.keySet()){
				sb.append("CONFIG.").append(key).append("=").append(JSON.toJSONString(comm.get(key), SerializerFeature.WriteDateUseDateFormat)).append(";\r\n");
			}
		}
		for(BigpipeCode c : smartCodes){
			String url = c.getUrl();
			if(!isAbsolute(url)){
				url = contextPath + url;
			}
			sb.append("smartCode['").append(c.getCode()).append("']={url:'").append(url).append("',msg:'").append(c.getMsg()).append("'};\r\n");
		}
		sb.append("</script>");
		return sb.toString();
	}
	
	public static abstract interface ConfigComm{
		public abstract void configComm(Map<String, Object> commVar, HttpServletRequest request, HttpServletResponse response);
	}
	public static String getJSBase() {
		return JSBase;
	}
	public static void setJSBase(String jSBase) {
		JSBase = jSBase;
	}
	public static String getCSSBase() {
		return CSSBase;
	}
	public static void setCSSBase(String cSSBase) {
		CSSBase = cSSBase;
	}
	public static String getIMAGEBase() {
		return IMAGEBase;
	}
	public static void setIMAGEBase(String iMAGEBase) {
		IMAGEBase = iMAGEBase;
	}
	public static String getContentPath() {
		return contentPath;
	}
	/**
	 * 增加错误码
	 * @param smartCode
	 */
	public static void addSmartCode(BigpipeCode smartCode){
		smartCodes.add(smartCode);
	}
	/**
	 * 增加错误码
	 * @param smartCode
	 */
	public static void addSmartCode(int code, String msg, String url){
		smartCodes.add(new BigpipeCode(code, msg, url));
	}
}
